package com.example.run_game;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Date;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.FragmentManager;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.AssetManager;
import android.graphics.Color;
import android.graphics.Paint;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.provider.Settings;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.MarkerOptionsCreator;
import com.google.android.gms.maps.model.PolylineOptions;

//Activity on screen when running

public class Run extends Activity {
	private RunSesh runSesh;
	LocationManager locationManager;
	private GoogleMap myMap;
	private LatLng centre;
	private boolean NO_LOCATION_YET;
	private ArrayList<Location> route;
	private ArrayList<LatLng> markers;
	private String routeID;
	private int updateNumber;
	private boolean paused;
	private long start;
	public Button stopButton;
	
	Handler handler = null;
	AssetManager am;
	
	Dialog subgoalDialog;

    public RunSesh getrunSesh()
    {
    	return runSesh;
    }
	
	public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        System.out.println("create triggered");
        setContentView(R.layout.activity_run);
        updateNumber = 0;
        start = 0;
        paused = true;
        setGPSHandler();
        int time = getIntent().getIntExtra("goaltime", 0);
        int dist= getIntent().getIntExtra("goaldist", 0);
        String[] weather = getIntent().getExtras().getStringArray("wm");
        centre = new LatLng(0,0);
        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        am = this.getAssets();
        SoundManager sounds = new SoundManager(this, am);
        
        //Create a custom dialog with the dialog_time.xml file
        subgoalDialog = new Dialog(this);
        subgoalDialog.setContentView(R.layout.subgoal_dialog);
        subgoalDialog.setTitle("Optional Bonuses"); 
        
        Button showBonus = (Button)findViewById(R.id.showBonus);
        showBonus.setOnClickListener(checkShowBonusPress);
        
        //Set all ui values to 0
        setSpeed(0);
		setTime("0");
		setKMDistance(0);
        
        runSesh = new RunSesh(this, (LocationManager) getSystemService(Context.LOCATION_SERVICE), this, dist, time, sounds, weather );        
        GPRStoggleSetup();
        
              
        ((TextView)subgoalDialog.findViewById (R.id.bonus0)).setText( runSesh.getSob().subobjectives[0].xpValue + ": ");
        ((TextView)subgoalDialog.findViewById (R.id.bonus1)).setText( runSesh.getSob().subobjectives[1].xpValue + ": ");
        ((TextView)subgoalDialog.findViewById (R.id.bonus2)).setText( runSesh.getSob().subobjectives[2].xpValue + ": ");
        ((TextView)subgoalDialog.findViewById (R.id.bonus3)).setText( runSesh.getSob().subobjectives[3].xpValue + ": ");
        ((TextView)subgoalDialog.findViewById (R.id.bonus4)).setText( runSesh.getSob().subobjectives[4].xpValue + ": ");   
        
        ((TextView)subgoalDialog.findViewById (R.id.bonusText0)).setText( runSesh.getSob().subobjectives[0].desc);
        ((TextView)subgoalDialog.findViewById (R.id.bonusText1)).setText( runSesh.getSob().subobjectives[1].desc);
        ((TextView)subgoalDialog.findViewById (R.id.bonusText2)).setText( runSesh.getSob().subobjectives[2].desc);
        ((TextView)subgoalDialog.findViewById (R.id.bonusText3)).setText( runSesh.getSob().subobjectives[3].desc );
        ((TextView)subgoalDialog.findViewById (R.id.bonusText4)).setText( runSesh.getSob().subobjectives[4].desc);
        
        Button cancelButton = (Button)subgoalDialog.findViewById(R.id.btn_close);
        cancelButton.setOnClickListener(closeBonusDia);
        subgoalDialog.show();
        
        //forcing portrait orientation
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
              
		//start thread
		Date d = new Date();
		Run.this.route = new ArrayList<Location>();
		Run.this.markers = new ArrayList<LatLng>();
		Run.this.routeID = "route"+d.getTime();
		initMap();
    }
	
	private OnClickListener checkShowBonusPress = new OnClickListener() 
    {
        public void onClick(View v) 
        {
        	Button cancelButton = (Button)subgoalDialog.findViewById(R.id.btn_close);
            cancelButton.setOnClickListener(closeBonusDia);
            
        	subgoalDialog.show();
        }
    };
    
    private OnClickListener closeBonusDia = new OnClickListener() 
    {
        public void onClick(View v) 
        {
                subgoalDialog.dismiss();                        
        }
    };

	private void initMap()
	{
		int result = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
		if (result == ConnectionResult.SUCCESS)
		{
			FragmentManager myFragmentManager = getFragmentManager();
			MapFragment myMapFragment = (MapFragment)myFragmentManager.findFragmentById(R.id.map);
			myMap = myMapFragment.getMap();
			myMap.setMyLocationEnabled(false);
			myMap.moveCamera(CameraUpdateFactory.newLatLng(new LatLng(51,-1)));
			myMap.moveCamera(CameraUpdateFactory.zoomBy(15));
			
			//myMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
			myMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
			//myMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
			//myMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
			
			//myMap.setOnMapClickListener(this);
		}
	}

	@Override
	public void onResume()
	{
		super.onResume();
		System.out.println("resume triggered");
		
		if (paused)
		{
			startTracking();
			System.out.println("run length = " + Run.this.route.size());
			paused = false;
		}
		if (!NO_LOCATION_YET)
		{
			System.out.println("timer started");
	        handler.removeCallbacks(UpdateTimeTask);
	        handler.postDelayed(UpdateTimeTask, 100);
		}
	}
    
    @Override
    protected void onPause()
    {
    	super.onPause();
        handler.removeCallbacks(UpdateTimeTask);
		System.out.println("pause triggered");
    }
    
    @Override
    protected void onStop()
    {
    	super.onStop();
		System.out.println("stop triggered");
    }
    
	public Handler getGPSHandler()
	{
		return handler;		
	}
    
    
	
	private void setGPSHandler()
	{
		handler = new Handler()
		{
			public void handleMessage(Message msg)
			{
				Date startD = new Date();
				if (msg.what == 1)
				{
					Location location = (Location) msg.obj;
					if (location == null)
						Log.e("Run.java","Location cast on line 68 resulted in null");
					else
					{
						Run.this.route.add(location);
						Run.this.markers.add(new LatLng(location.getLatitude(),location.getLongitude()));
						

						if (Run.this.start == 0)
						{
							Run.this.start = System.currentTimeMillis();
						}
				        handler.removeCallbacks(UpdateTimeTask);
				        handler.postDelayed(UpdateTimeTask, 100);
				        
						updateCentre(location);
						updateMap(location);
						
						if(route.size() == 1)
						{
							runSesh.actOnLocationUpdate(location, location);
						}
						else
						{
							runSesh.actOnLocationUpdate(route.get(route.size()-2), location);
						}
												
						if (NO_LOCATION_YET)
						{
							NO_LOCATION_YET=false;
						}
					}
				}
				Date end = new Date();
				System.out.println("Time to process GPS signal = "+(end.getTime()-startD.getTime())+"ms");
			}
		};
	}
    
	public ArrayList<Location> getRoute()
	{
	    return route;
	}
	
	protected void updateMap(Location location)
	{
		int result = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
		if (result == ConnectionResult.SUCCESS)
		{
			FragmentManager myFragmentManager = getFragmentManager();
			MapFragment myMapFragment = (MapFragment)myFragmentManager.findFragmentById(R.id.map);
			myMap = myMapFragment.getMap();
			
			myMap.setMyLocationEnabled(false);
			PolylineOptions opt = new PolylineOptions();
			opt.addAll(Run.this.markers);
			opt.width(3);
			
			//add circle to show player position
			myMap.clear();
			MarkerOptions mo = new MarkerOptions();
			mo.position(new LatLng(location.getLatitude(),location.getLongitude()));
			myMap.addMarker(mo);
			myMap.addPolyline(opt);
			addCheckpointMarkers(myMap);
			drawCheckpointArrows(myMap,location);
			
			if (Run.this.updateNumber % 5 == 0)
			{
				myMap.moveCamera(CameraUpdateFactory.newLatLng(Run.this.centre));
				System.out.println("Moving map to " + Run.this.centre.latitude + ", " + Run.this.centre.longitude);
				//myMap.moveCamera(CameraUpdateFactory.zoomBy(10));
			}
			updateNumber++;
		}
	}

	private void addCheckpointMarkers(GoogleMap myMap2)
	{
		if (runSesh.getCurrChoice() == null)
			return;
		for (Checkpoint c : runSesh.getCheckpoints())
		{
			MarkerOptions mo = new MarkerOptions();
			mo.position(new LatLng(c.location.getLatitude(),c.location.getLongitude()));
			mo.draggable(false);
			mo.title("(VISITED) "+c.description);
			mo.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE));
			myMap2.addMarker(mo);
		}
		for (Checkpoint c : runSesh.getCurrChoice().getAllChoices())
		{
			MarkerOptions mo = new MarkerOptions();
			mo.position(new LatLng(c.location.getLatitude(),c.location.getLongitude()));
			mo.draggable(false);
			mo.title(c.description);
			mo.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_YELLOW));
			myMap2.addMarker(mo);
		}
	}

	private void drawCheckpointArrows(GoogleMap myMap2, Location location)
	{
		if (runSesh.getCurrChoice() == null)
			return;
		PolylineOptions opt = new PolylineOptions();
		for (Checkpoint c: runSesh.getCurrChoice().getAllChoices())
		{
			Log.d("mapupdate",runSesh.getCurrChoice().getAllChoices().length+"");
			ArrayList<Location> arrow = makeArrow(location, location);
			opt.addAll(Run.this.markers);
			opt.color(Color.YELLOW);
			opt.width(3);
		}
	}

	private ArrayList<Location> makeArrow(Location from, Location to)
	{
		ArrayList<Location> arrow = new ArrayList<Location>();
		arrow.add(from);
		
		return arrow;
	}

	protected void updateCentre(Location location)
	{
		double lat = Run.this.centre.latitude;
		double lon = Run.this.centre.longitude;
		if (lat == 0d && lon == 0d)
			Run.this.centre = new LatLng(location.getLatitude(),location.getLongitude());
		else 
		{
			lat+=location.getLatitude();
			lon+=location.getLongitude();
			Run.this.centre = new LatLng(lat/2,lon/2);		
		}
	}

	public void warnUserGPSDisabled()
	{
    	//TODO: add a dialog making them enable GPS
    	System.out.println("GPS IS NOT ENABLED");
		((TextView)findViewById (R.id.textView1)).setText("GPS IS NOT ENABLED");
		
	    Intent settingsIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
	    startActivity(settingsIntent);
		return;
	}
	
    private void GPRStoggleSetup()
    {		
    	route = new ArrayList<Location>();

    	stopButton = (Button) findViewById(R.id.stop);
			
		if (stopButton == null) return;
		stopButton.setOnClickListener(new OnClickListener()
		{
			
			@Override
			public void onClick(View v)
			{
				//stop thread
				if (NO_LOCATION_YET)
				{
					Toast.makeText(getApplicationContext(), "Cannot save route before GPS satellite connection.", Toast.LENGTH_SHORT).show();
					return;
				}
				System.out.println("Tracking stopped.");
				System.out.println("run length = " + Run.this.route.size());
		    	Run.this.paused = true;
				runSesh.getGPSTracker().stopTracking();
				writeToXML();
				Intent intent = new Intent(getBaseContext(), PostRunInformation.class);
				Bundle bundle = new Bundle();
				bundle.putString("path", Run.this.routeID);
				bundle.putInt("xp", runSesh.getPlayer().getTotalScore());
				Log.d("Score: ", "Score sent to run screen as "+ runSesh.getScoreManager().score);
				bundle.putInt("calories", runSesh.getCalories());
				intent.putExtras(bundle);
				startActivity(intent);		
			}
		});
    }
    
    private void writeToXML()
    {
    	try {
    		deleteFile(Run.this.routeID);
			FileOutputStream fos = openFileOutput(Run.this.routeID,Context.MODE_APPEND);
			if (route.size()==0)
    		{
    			fos.write(
					("<Route>\n"+
					"\t<Location>\n"+
					"\t\t<Time>1356071710492</Time>\n"+
					"\t\t<Latitude>52.074893830672586</Latitude>\n"+
					"\t\t<Longitude>-0.0509241959093702</Longitude>\n"+
					"\t\t<Altitude>159.25635636085732</Altitude>\n"+
					"\t</Location>\n"+
					"\t<Location>\n"+
					"\t\t<Time>1356071712492</Time>\n"+
					"\t\t<Latitude>51.074893830672586</Latitude>\n"+
					"\t\t<Longitude>-0.1509241959093702</Longitude>\n"+
					"\t\t<Altitude>159.25635636085732</Altitude>\n"+
					"\t</Location>\n"+
					"\t<Location>\n"+
					"\t\t<Time>1356071714492</Time>\n"+
					"\t\t<Latitude>51.074893830672586</Latitude>\n"+
					"\t\t<Longitude>-0.0509241959093702</Longitude>\n"+
					"\t\t<Altitude>159.25635636085732</Altitude>\n"+
					"\t</Location>\n"+
					"\t<Location>\n"+
					"\t\t<Time>1356076710492</Time>\n"+
					"\t\t<Latitude>52.074893830672586</Latitude>\n"+
					"\t\t<Longitude>-0.0509241959093702</Longitude>\n"+
					"\t\t<Altitude>159.25635636085732</Altitude>\n"+
					"\t</Location>\n").getBytes());
    		}
			else
			{
				fos.write("<Route>\n".getBytes());
				for (Location location : Run.this.route)
				{
					String xml=
							"<Location>\n" +
									"\t<Time>"+location.getTime()+"</Time>\n" +
									"\t<Latitude>"+location.getLatitude()+"</Latitude>\n" +
									"\t<Longitude>"+location.getLongitude()+"</Longitude>\n" +
									"\t<Altitude>"+location.getAltitude()+"</Altitude>\n" +
							"</Location>\n"
							;
					fos.write(xml.getBytes());
				}
			}
			fos.write("</Route>\n".getBytes());
			fos.close();
			
		} catch (IOException e) {
			Log.e("Run.java", "ROUTE FILE COULD NOT BE ACCESSED\n");
			e.printStackTrace();
		}
    	
    	writeCheckpointFile();
    }

	private void writeCheckpointFile()
	{
		if (runSesh.getCheckpoints().size() == 0)
			return;
		String filename = Run.this.routeID.replaceAll("route", "checkpoint");
		String contents = "";
		for (Checkpoint c : runSesh.getCheckpoints())
			contents += c.name+" "+c.location.getLatitude()+" "+c.location.getLongitude()+"\n";
		deleteFile(filename);
		try
		{
			FileOutputStream fos = openFileOutput(filename,Context.MODE_APPEND);
			fos.write(contents.getBytes());
			fos.close();
		} catch (IOException e)
		{
			e.printStackTrace();
		}
		System.out.println(contents);
	}

	protected String getRouteXML()
	{
		FileInputStream f;
		StringBuffer rewte;
		if (route.size() == 0)
			return "<Route>\n" +
					"\t<Location>\n"+
					"\t\t<Time>1356071710492</Time>\n"+
					"\t\t<Latitude>52.074893830672586</Latitude>\n"+
					"\t\t<Longitude>-0.0509241959093702</Longitude>\n"+
					"\t\t<Altitude>159.25635636085732</Altitude>\n"+
					"\t</Location>\n"+
					"\t<Location>\n"+
					"\t\t<Time>1356071712492</Time>\n"+
					"\t\t<Latitude>51.074893830672586</Latitude>\n"+
					"\t\t<Longitude>-0.1509241959093702</Longitude>\n"+
					"\t\t<Altitude>159.25635636085732</Altitude>\n"+
					"\t</Location>\n"+
					"\t<Location>\n"+
					"\t\t<Time>1356071714492</Time>\n"+
					"\t\t<Latitude>51.074893830672586</Latitude>\n"+
					"\t\t<Longitude>-0.0509241959093702</Longitude>\n"+
					"\t\t<Altitude>159.25635636085732</Altitude>\n"+
					"\t</Location>\n"+
					"\t<Location>\n"+
					"\t\t<Time>1356071710492</Time>\n"+
					"\t\t<Latitude>52.074893830672586</Latitude>\n"+
					"\t\t<Longitude>-0.0509241959093702</Longitude>\n"+
					"\t\t<Altitude>159.25635636085732</Altitude>\n"+
					"\t</Location>\n" +
					"</Route>\n";
		else
			rewte = new StringBuffer("");
		try
		{
			f = openFileInput(Run.this.routeID);
			int ch;
			while ((ch = f.read()) != -1)
				rewte.append((char)ch);
			((TextView)findViewById (R.id.textView1)).setText(rewte.toString());
		} catch (FileNotFoundException e)
		{
			e.printStackTrace();
		} catch (IOException e)
		{
			e.printStackTrace();
		}
		return rewte.toString();
	}

	protected void startTracking() {
        NO_LOCATION_YET = true;
        
        Toast.makeText(getApplicationContext(), "Connecting to GPS satellite",Toast.LENGTH_LONG).show();
        //dialog.setTitle("PLACEHOLDER TITLE");
		runSesh.getGPSTracker().startTracking();		
	}
	
	/*
	 * Setters for the run statistics bar
	 */
	
	protected void setKMDistance(double distance) 
	{
		distance = distance /1000;
		DecimalFormat nf = new DecimalFormat("#.###");
		((TextView)findViewById (R.id.distance_val)).setText(nf.format(distance)+"km");	
	} 
	
	protected void setTargetPercent(int percent) 
	{
		((TextView)findViewById (R.id.progress_val)).setText(percent+"% of "+ runSesh.getTarget());	
	} 
	
	protected void setTime(String result) 
	{
		((TextView)findViewById (R.id.time_val)).setText(result);	
	} 
	
	//in m/s
	protected void setSpeed(double val) 
	{	
	    double mps = val;
	    double kph = mps * 60 * 60 /1000;
		DecimalFormat df = new DecimalFormat("#.#");
		((TextView)findViewById (R.id.speed_val)).setText(df.format(mps)+"m/s   /   " + df.format(kph)+"kph");	
	} 
	

	protected void setCheckpoints(int val)
	{	       
		((TextView)findViewById (R.id.checkpoints_val)).setText(""+val);	
	} 
	
	protected void setCalories(int val)
	{	       
		((TextView)findViewById (R.id.calories_val)).setText(""+val);	
	} 
		
	protected void setRunProgress(int curr, int max, int dist_or_time) {
	       
		String text = "";
		if(dist_or_time == 0)
		{
			text = curr+"/"+max+"m";
		}
		if(dist_or_time == 1)
		{
			//More time processing needed to put in right format
			text = curr+"/"+max;
		}
		((TextView)findViewById (R.id.progress_val)).setText(text);	
	} 
	
	/*
	 * Setters for the progress/experience bar
	 */
	
	//updates the progress/percentage complete of experience bar
	protected void setProgressBarExp(int exp)
	{	       
		//Log.d("GAME: ", "Progress Bar XP set:" + exp);
		((ProgressBar)findViewById (R.id.progressBar)).setProgress(exp);	
	}
	
	//updates the upper and lower bounds on the experience bar
	
	protected void setLevelUp(int lvl)
	{	      
		//set lower bound to be the new level
		((TextView)findViewById (R.id.level_lower_text)).setText(""+lvl);
		//set upper bound to be the new level + 1
		((TextView)findViewById (R.id.level_upper_text)).setText(""+(lvl+1));		
	}
	

	@Override
	public void onBackPressed() {
	    new AlertDialog.Builder(this)
	        .setIcon(android.R.drawable.ic_dialog_alert)
	        .setTitle("Warning!")
	        .setMessage("Are you sure you want to quit your run? Your progress will not be saved.")
	        .setPositiveButton("Yes", new DialogInterface.OnClickListener()
	    {
	        @Override
	        public void onClick(DialogInterface dialog, int which) {
	        	Run.this.paused = true;
	    		runSesh.getGPSTracker().stopTracking();
	            finish();    
	        }

	    })
	    .setNegativeButton("No", null)
	    .show();
	}
	
	private Runnable UpdateTimeTask = new Runnable()
	{
		public void run()
		{
			final long start = Run.this.start;
			long millis = System.currentTimeMillis() - Run.this.start;
			String result = Utils.formatMilliTime(millis, true);
			Run.this.setTime(result);
			
			handler.postAtTime(this, new Date().getTime()+1000);
            handler.postDelayed(this, 107);
		}
	};

	public void setObjectiveAchieved(int index)
	{
		TextView tv = null;
		TextView xp = null;
		
		switch(index)
		{
		case 0:
			tv = (TextView) subgoalDialog.findViewById(R.id.bonusText0);
			xp = (TextView) subgoalDialog.findViewById(R.id.bonus0);
			break;
		case 1:
			tv = (TextView) subgoalDialog.findViewById(R.id.bonusText1);
			xp = (TextView) subgoalDialog.findViewById(R.id.bonus1);
			break;
		case 2:
			tv = (TextView) subgoalDialog.findViewById(R.id.bonusText2);
			xp = (TextView) subgoalDialog.findViewById(R.id.bonus2);
			break;
		case 3:
			tv = (TextView) subgoalDialog.findViewById(R.id.bonusText3);
			xp = (TextView) subgoalDialog.findViewById(R.id.bonus3);
			break;
		case 4:
			tv = (TextView) subgoalDialog.findViewById(R.id.bonusText4);
			xp = (TextView) subgoalDialog.findViewById(R.id.bonus4);
			break;
		default:
			break;	
		}	
		if(tv != null && xp != null)
		{
			tv.setPaintFlags(tv.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
			xp.setPaintFlags(xp.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
		}
	}
	
	
	
}

